﻿using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Common;
using DomainModel;
using ForumEngine.Models;

namespace ViewServices
{
    class ForumViewService : IForumViewService
    {
        private readonly IUserViewService _userViewService;
        private readonly IPathViewService _pathViewService;

        public ForumViewService(IUserViewService userViewService, IPathViewService pathViewService)
        {
            _userViewService = userViewService;
            _pathViewService = pathViewService;
        }

        public List<SectionModel> GetAllSections()
        {
            using (var domainModel = new DataAccess.DomainModel())
            {
                return domainModel.Sections.Where(x => !x.ParentSectionId.HasValue).ToList().Select(s => GetSection(domainModel, s)).ToList();
            }
        }

        public SectionModel GetSection(long sectionId)
        {
            using (var domainModel = new DataAccess.DomainModel())
            {
                var section = domainModel.Sections.Find(sectionId);
                var model = GetSection(domainModel, section);

                if (section.IsForum)
                {
                    foreach (var thread in section.Threads)
                    {
                        model.Threads.Add(GetSectionThread(thread.Id));
                    }
                }

                return model;
            }
        }

        private SectionModel GetSection(DataAccess.DomainModel domainModel, Section section)
        {
            var requestContext = ((MvcHandler) HttpContext.Current.Handler).RequestContext;

            var model = new SectionModel
            {
                Name = section.Name,
                Id = section.Id,
                Url = new UrlHelper(requestContext).RouteUrl(new { application = "Forum", action = "Section", id = section.Id }),
                Description = section.Description,
                Forums = section.Sections.Select(s => GetSectionForum(domainModel, s)).ToList(),
                Threads = new List<SectionThreadModel>(),
                Path = _pathViewService.GetFullPathSection(section.Id, true)
            };

            return model;
        }

        private static void GetChildForums(DataAccess.DomainModel domainModel, long forumId, ICollection<long> ids)
        {
            foreach (var subForumId in domainModel.Sections.Where(s => s.ParentSectionId == forumId).Select(s => s.Id))
            {
                ids.Add(subForumId);
                GetChildForums(domainModel, subForumId, ids);
            }
        }

        private SectionForumModel GetSectionForum(DataAccess.DomainModel domainModel, Section forum)
        {
            var model = new SectionForumModel
            {
                Name = forum.Name,
                Description = forum.Description,
                Url = MvcHelper.UrlHelper.RouteUrl(new { application = "Forum", action = "Section", id = forum.Id }),
                HasNewPosts = false, // TBD
                Id = forum.Id
            };

            var forumIds = new List<long> { forum.Id };
            GetChildForums(domainModel, forum.Id, forumIds);

            var threadIds = domainModel.Threads.Where(t => forumIds.Contains(t.SectionId)).Select(t => t.Id);

            model.Threads = threadIds.Count();
            model.Posts = domainModel.Posts.Count(p => threadIds.Contains(p.ThreadId));

            var lastPost = domainModel.Posts.Where(p => threadIds.Contains(p.ThreadId)).OrderByDescending(p => p.Created).FirstOrDefault();

            if (lastPost != null)
            {
                model.LastAuthor = _userViewService.GetUser(lastPost.Author.Id);
                model.LastPostTime = lastPost.Created;
                model.LastPostTitle = lastPost.Title;
                if (string.IsNullOrEmpty(model.LastPostTitle))
                {
                    model.LastPostTitle = lastPost.Thread.Name;
                }
                model.LastPostUrl = MvcHelper.UrlHelper.RouteUrl(new { application = "Forum", action = "Thread", id = lastPost.ThreadId, page = "last" });
            }

            model.Moderators = new List<UserModel>();

            return model;
        }

        public SectionThreadModel GetSectionThread(long threadId)
        {
            using (var domainModel = new DataAccess.DomainModel())
            {
                var thread = domainModel.Threads.Find(threadId);
                return GetSectionThread(domainModel, thread);
            }
        }

        private const int PostsPerPage = 20;

        public ThreadModel GetThread(long threadId, int pageNumber)
        {
            using (var domainModel = new DataAccess.DomainModel())
            {
                var thread = domainModel.Threads.Find(threadId);

                var posts = domainModel.Posts.Where(p => p.ThreadId == threadId).OrderBy(p => p.Created);

                var postsCount = posts.Count();
                var pagesCount = (postsCount + PostsPerPage - 1) / PostsPerPage;

                var model = new ThreadModel
                {
                    Id = thread.Id,
                    Name = thread.Name,
                    Description = thread.Description,
                    Page = pageNumber,
                    Pages = pagesCount,
                    Posts = posts.Skip((pageNumber - 1) / PostsPerPage).Take(PostsPerPage).ToList().Select(p => GetPost(p.Id)).ToList(),
                    Path = _pathViewService.GetFullPathThread(thread.Id)
                };

                return model;
            }
        }

        public int GetThreadPostCount(long threadId)
        {
            using (var domainModel = new DataAccess.DomainModel())
            {
                return domainModel.Posts.Where(p => p.ThreadId == threadId).OrderBy(p => p.Created).Count();
            }
        }

        public int GetThreadLastPage(long threadId)
        {
            var postsCount = GetThreadPostCount(threadId);
            var pagesCount = (postsCount + PostsPerPage - 1) / PostsPerPage;
            return pagesCount;
        }

        private SectionThreadModel GetSectionThread(DataAccess.DomainModel domainModel, Thread thread)
        {
            var posts = domainModel.Entry(thread).Collection(t => t.Posts).Query();

            var model = new SectionThreadModel
            {
                Id = thread.Id,
                Name = thread.Name,
                Description = thread.Description,
                Url = MvcHelper.UrlHelper.RouteUrl(new
                {
                    application = Constants.Applications.Forum.Name,
                    action = Constants.Applications.Forum.Actions.Thread,
                    id = thread.Id
                }),
                Posts = posts.Count(),
                Created = thread.Created,
                CreatedBy = _userViewService.GetUser(thread.Author.Id)
            };

            if (model.Posts > 0)
            {
                var lastPost = posts.OrderByDescending(p => p.Created).First();
                model.LastPostTime = lastPost.Created;
                model.LastPostTitle = lastPost.Title;
                model.LastAuthor = _userViewService.GetUser(lastPost.Author.Id);
                model.LastPostUrl = model.Url + "#" + lastPost.Id;
            }

            return model;
        }

        public PostModel GetPost(long postId)
        {
            using (var domainModel = new DataAccess.DomainModel())
            {
                var post = domainModel.Posts.Find(postId);
                var model = new PostModel
                {
                    Id = post.Id,
                    Title = post.Title,
                    Text = post.Text,
                    Created = post.Created,
                    Author = _userViewService.GetUser(post.Author.Id),
                    Modified = post.Modified,
                    ModifiedBy = _userViewService.GetUser(post.ModifiedBy.Id)
                };

                return model;
            }
        }
    }
}
